package ldh.im.fxbase.service;

import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import ldh.im.fxbase.util.FxThreadUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;

public class GifViewService implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(GifViewService.class);

    private String imagePath;
    private ImageInputStream iis = null;
    private ImageReader reader = null;
    private int numImages = 0;
    private int delayTime = 200;
    private int index = 0;
    private volatile boolean isRunning = true;
    private ImageView imageView = null;

    public GifViewService(String imagePath) {
        this.imagePath = imagePath;
    }

    public synchronized Image getFirstImage() {
        if (iis == null) {
            try {
                loadData();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (!isRunning) return null;
        try {
            BufferedImage bufferedImage = reader.read(0);
            return SwingFXUtils.toFXImage(bufferedImage, null);
        } catch (Exception e) {
            throw new RuntimeException("获取gif第一张图片失败");
        }
    }

    public void animateView(ImageView imageView) {
        this.imageView = imageView;
        this.isRunning = true;
        Thread thread = new Thread(this);
        thread.setDaemon(true);
        thread.start();
    }

    public void reset() {
        this.isRunning = false;
    }

    public void update() {
        LOGGER.info("gif update");
        animateView(imageView);
    }

    public synchronized void dispose() {
        this.isRunning = false;
        this.imageView = null;
        Thread.currentThread().interrupt();
        close();
    }

    @Override
    public void run() {
        while(isRunning) {
            LOGGER.info("gif animate is running, index: {}, total: {}", index, numImages);
            if (index >= numImages) {
                index = 0;
                close();
                break;
            }

            BufferedImage bufferedImage = readImage(index++);
            if(bufferedImage != null) {
                FxThreadUtil.runLater(()->{
                    if (imageView != null && isRunning) {
                        imageView.setImage(SwingFXUtils.toFXImage(bufferedImage, null));
                    }
                });
            }

            if (isRunning) {
                try {
                    Thread.sleep(delayTime);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private synchronized BufferedImage readImage(int index) {
        try {
            BufferedImage bufferedImage = reader.read(index++);
            return bufferedImage;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private void loadData() throws IOException {
        File file = new File(imagePath);
        iis = ImageIO.createImageInputStream(file);
        Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
        if (readers.hasNext()) {
            reader = readers.next();
            reader.setInput(iis);
            if (!isRunning) return;
            numImages = reader.getNumImages(true); // 获取GIF中的帧数
            System.out.println("numImages: " + numImages);
            IIOMetadata metadata = reader.getStreamMetadata();
            if (metadata != null) {
                String[] metadataNames = metadata.getMetadataFormatNames();
                for (String name : metadataNames) {
                    if (name.equalsIgnoreCase("javax_imageio_gif_image_1.0")) {
                        Node node = metadata.getAsTree(name);
                        NodeList graphicControlExtensions = node.getChildNodes();
                        for (int i = 0; i < graphicControlExtensions.getLength(); i++) {
                            Node graphicControlExtension = graphicControlExtensions.item(i);
                            if ("GraphicControlExtension".equals(graphicControlExtension.getNodeName())) {
                                NamedNodeMap attributes = graphicControlExtension.getAttributes();
                                Node delayNode = attributes.getNamedItem("delayTime"); // In milliseconds
                                if (delayNode != null) {
                                    delayTime = Integer.parseInt(delayNode.getNodeValue());
                                    System.out.println("delayTime:" + delayTime);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private void close() {
        try {
            if (reader != null) {
                reader.dispose();
            }
            if (iis != null) {
                iis.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
